/*
 * ==========================================================================*\
 * | $Id: UiFactory.java 360 2011-02-20 19:43:41Z vtwoods@gmail.com $
 * |*-------------------------------------------------------------------------*|
 * | Copyright (C) 2009 Virginia Tech | | This file is part of CloudSpace. | |
 * CloudSpace is free software; you can redistribute it and/or modify | it under
 * the terms of the GNU General Public License as published | by the Free
 * Software Foundation; either version 3 of the License, or | (at your option)
 * any later version. | | CloudSpace is distributed in the hope that it will be
 * useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General
 * Public License for more details. | | You should have received a copy of the
 * GNU General Public License | along with CloudSpace; if not, see
 * <http://www.gnu.org/licenses/>.
 * \*==========================================================================
 */

package student.web.internal;

import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import org.zkoss.idom.Document;
import org.zkoss.zk.ui.http.SimpleUiFactory;
import org.zkoss.zk.ui.metainfo.InitiatorInfo;
import org.zkoss.zk.ui.metainfo.PageDefinition;
import org.zkoss.zk.ui.sys.RequestInfo;
import org.zkoss.zkplus.databind.AnnotateDataBinderInit;


// -------------------------------------------------------------------------
/**
 * A custom UI factory for student ZK pages that implicitly adds an
 * {@link Initializer} to any page definitions it loads.
 * 
 * @author Stephen Edwards
 * @author Last changed by $Author: vtwoods@gmail.com $
 * @version $Revision: 360 $, $Date: 2010-11-17 22:10:44 -0500 (Wed, 17 Nov
 *          2010) $
 */
public class UiFactory extends SimpleUiFactory
{
    // ----------------------------------------------------------
    @Override
    public PageDefinition getPageDefinition( RequestInfo ri, String path )
    {
        return wrap( super.getPageDefinition( ri, path ) );
    }


    // ----------------------------------------------------------
    @Override
    public PageDefinition getPageDefinitionDirectly(
        RequestInfo ri,
        Document content,
        String extension )
    {
        return wrap( super.getPageDefinitionDirectly( ri, content, extension ) );
    }


    // ----------------------------------------------------------
    @Override
    public PageDefinition getPageDefinitionDirectly(
        RequestInfo ri,
        Reader reader,
        String extension ) throws IOException
    {
        return wrap( super.getPageDefinitionDirectly( ri, reader, extension ) );
    }


    // ----------------------------------------------------------
    @Override
    public PageDefinition getPageDefinitionDirectly(
        RequestInfo ri,
        String content,
        String extension )
    {
        return wrap( super.getPageDefinitionDirectly( ri, content, extension ) );
    }


    // ----------------------------------------------------------
    @SuppressWarnings("unchecked")
    private PageDefinition wrap( PageDefinition pagedef )
    {

        if ( pagedef != null )
        {
            // First, get the _initdefs field, if we haven't already
            if ( _initdefs == null )
            {
                for ( Field f : PageDefinition.class.getDeclaredFields() )
                {
                    if ( f.getName().equals( "_initdefs" ) )
                    {
                        f.setAccessible( true );
                        _initdefs = f;
                        break;
                    }
                }
            }

            // Now look for an existing initiator
            try
            {
                List<InitiatorInfo> list = (List<InitiatorInfo>)_initdefs.get( pagedef );
                if ( list != null )
                {
                    // We need to get the initiator info's internal field
                    if ( _init == null )
                    {
                        for ( Field f : InitiatorInfo.class.getDeclaredFields() )
                        {
                            if ( f.getName().equals( "_init" ) )
                            {
                                f.setAccessible( true );
                                _init = f;
                                break;
                            }
                        }
                    }

                    // Now, scan the list looking for the right one
                    for ( InitiatorInfo info : list )
                    {
                        Object i = _init.get( info );
                        if ( i != null
                            && ( i == Initializer.class || AnnotateDataBinderInit.class.isAssignableFrom( i.getClass() ) ) )
                        {
                            // If found, don't add it again
                            return pagedef;
                        }
                    }
                }
            }
            catch ( Exception e )
            {
                // swallow it
                e.printStackTrace();
            }

            // If we didn't find this initiator, then add it
            pagedef.addInitiatorInfo( new InitiatorInfo( Initializer.class,
                (Map<?, ?>)null ) );
        }
        return pagedef;
    }

    // ----------------------------------------------------------
    private static Field _initdefs = null;

    private static Field _init = null;
}
